package sandbox

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"

	"pkg/models"
	"pkg/sandbox/cgroups"
	"pkg/sandbox/namespaces"
	"pkg/sandbox/seccomp"
	"pkg/utils/logger"
)

// Sandbox 封装沙箱功能
type Sandbox struct {
	input         *models.InputStruct
	languageCfg   *models.LanguageConfig
	workDir       string
	executable    string
	namespaceMgr  *namespaces.NamespaceManager
	cgroupMgr     *cgroups.CgroupManager
	seccompFilter *seccomp.BPFProgram
}

// NewSandbox 创建新的沙箱实例
func NewSandbox(input *models.InputStruct) *Sandbox {
	return &Sandbox{
		input: input,
	}
}

// Initialize 初始化沙箱环境
func (s *Sandbox) Initialize() error {
	tempDir := fmt.Sprintf("sandbox-%d", s.input.SubmissionID)
	// 创建临时工作目录
	dir, err := os.MkdirTemp("", tempDir)
	if err != nil {
		return fmt.Errorf("failed to create temp dir: %w", err)
	}
	s.workDir = dir

	// 获取语言配置
	cfg, err := s.getLanguageConfig()
	if err != nil {
		return fmt.Errorf("failed to get language config: %w", err)
	}
	s.languageCfg = cfg

	// 创建seccomp过滤器
	s.seccompFilter = seccomp.DefaultSandbox()
	for _, syscallName := range s.languageCfg.AllowSysCalls {
		syscallNum, ok := seccomp.SyscallMap[syscallName]
		if !ok {
			return fmt.Errorf("unknown syscall: %s", syscallName)
		}
		s.seccompFilter.AllowSyscall(syscallNum)
	}

	// 准备根文件系统 - 将工作目录内容复制到根文件系统中
	if err := s.prepareRootFS(); err != nil {
		return fmt.Errorf("failed to prepare rootfs: %w", err)
	}

	// 创建命名空间管理器（带Seccomp支持）
	s.namespaceMgr = namespaces.NewNamespaceManagerWithSeccomp(
		&namespaces.NamespaceConfig{
			UTS:    true,
			PID:    true,
			Mount:  true,
			RootFS: s.getRootFS(),
		},
		s.seccompFilter,
	)

	// 创建cgroup管理器
	cgroupName := tempDir
	s.cgroupMgr = cgroups.NewCgroupManager(cgroupName)
	if err := s.cgroupMgr.Create(); err != nil {
		return fmt.Errorf("failed to create cgroup: %w", err)
	}

	// 设置资源限制
	memoryMB := s.input.ResourcesLimits.MemoryBytes / (1024 * 1024)
	if err := s.cgroupMgr.SetLimits(
		strconv.Itoa(s.input.ResourcesLimits.CpuTime*1000)+" 1000000", // CPU时间限制
		int(memoryMB), // 内存限制(MB)
		10,            // 最大进程数
	); err != nil {
		return fmt.Errorf("failed to set cgroup limits: %w", err)
	}

	return nil
}

// getRootFS 获取根文件系统路径
func (s *Sandbox) getRootFS() string {
	// 实际应用中应该根据语言配置不同的根文件系统
	language := s.input.Language
	if language == "python3" {
		language = "python" // python3 使用 python 目录
	}
	return "/opt/sandbox/rootfs/" + language
}

// prepareRootFS 准备根文件系统，将工作目录内容复制到根文件系统中
func (s *Sandbox) prepareRootFS() error {
	rootFS := s.getRootFS()

	// 确保根文件系统目录存在
	if err := os.MkdirAll(rootFS, 0755); err != nil {
		return fmt.Errorf("failed to create rootfs directory: %w", err)
	}

	// 将工作目录的内容复制到根文件系统中
	if err := s.copyWorkDirToRootFS(); err != nil {
		return fmt.Errorf("failed to copy work directory to rootfs: %w", err)
	}

	return nil
}

// copyWorkDirToRootFS 将工作目录内容复制到根文件系统
func (s *Sandbox) copyWorkDirToRootFS() error {
	rootFS := s.getRootFS()

	// 读取工作目录中的所有文件
	entries, err := os.ReadDir(s.workDir)
	if err != nil {
		return fmt.Errorf("failed to read work directory: %w", err)
	}

	for _, entry := range entries {
		srcPath := filepath.Join(s.workDir, entry.Name())
		dstPath := filepath.Join(rootFS, entry.Name())

		if entry.IsDir() {
			// 复制目录
			if err := s.copyDir(srcPath, dstPath); err != nil {
				return fmt.Errorf("failed to copy directory %s: %w", entry.Name(), err)
			}
		} else {
			// 复制文件
			if err := s.copyFile(srcPath, dstPath); err != nil {
				return fmt.Errorf("failed to copy file %s: %w", entry.Name(), err)
			}
		}
	}

	return nil
}

// copyDir 复制目录
func (s *Sandbox) copyDir(src, dst string) error {
	if err := os.MkdirAll(dst, 0755); err != nil {
		return err
	}

	entries, err := os.ReadDir(src)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		srcPath := filepath.Join(src, entry.Name())
		dstPath := filepath.Join(dst, entry.Name())

		if entry.IsDir() {
			if err := s.copyDir(srcPath, dstPath); err != nil {
				return err
			}
		} else {
			if err := s.copyFile(srcPath, dstPath); err != nil {
				return err
			}
		}
	}

	return nil
}

// copyFile 复制文件
func (s *Sandbox) copyFile(src, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dstFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	_, err = dstFile.ReadFrom(srcFile)
	if err != nil {
		return err
	}

	// 获取源文件的权限
	srcInfo, err := srcFile.Stat()
	if err != nil {
		return err
	}

	// 设置目标文件的权限
	if err := os.Chmod(dst, srcInfo.Mode()); err != nil {
		return err
	}

	return nil
}

// getLanguageConfig 获取语言配置
func (s *Sandbox) getLanguageConfig() (*models.LanguageConfig, error) {
	// 实际应用中应该从配置文件或数据库加载
	switch s.input.Language {
	case "cpp":
		return &models.LanguageConfig{
			CompileCmd: "g++ -O2 -std=c++17 -o main main.cpp",
			RunCmd:     "./main",
			AllowSysCalls: []string{
				"read", "write", "open", "close", "fstat",
				"mmap", "munmap", "mprotect", "brk", "arch_prctl",
				"exit", "exit_group", "rt_sigreturn",
			},
		}, nil
	case "python", "python3":
		return &models.LanguageConfig{
			RunCmd: "python3 main.py",
			AllowSysCalls: []string{
				"read", "write", "open", "close", "fstat",
				"mmap", "munmap", "mprotect", "brk", "arch_prctl",
				"exit", "exit_group", "rt_sigreturn", "clone", "execve",
			},
		}, nil
	case "java":
		return &models.LanguageConfig{
			CompileCmd: "javac Main.java",
			RunCmd:     "java Main",
			AllowSysCalls: []string{
				"read", "write", "open", "close", "fstat",
				"mmap", "munmap", "mprotect", "brk", "arch_prctl",
				"exit", "exit_group", "rt_sigreturn", "clone", "futex",
			},
		}, nil
	default:
		return nil, fmt.Errorf("unsupported language: %s", s.input.Language)
	}
}

/*
*
Compile 编译代码
*/
func (s *Sandbox) Compile() error {
	// 保存代码到文件
	ext := map[string]string{
		"cpp":     ".cpp",
		"python":  ".py",
		"python3": ".py",
		"java":    ".java",
	}[s.input.Language]

	codePath := filepath.Join(s.workDir, "main"+ext)
	if err := os.WriteFile(codePath, []byte(s.input.Code), 0644); err != nil {
		return fmt.Errorf("failed to write code: %w", err)
	}

	if s.languageCfg.CompileCmd == "" {
		return nil // 无需编译
	}

	// 执行编译命令
	cmdParts := strings.Split(s.languageCfg.CompileCmd, " ")
	cmd := exec.Command(cmdParts[0], cmdParts[1:]...)
	cmd.Dir = s.workDir

	// 捕获编译输出
	var stdoutBuf, stderrBuf bytes.Buffer
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = &stderrBuf

	if err := cmd.Run(); err != nil {
		// 保存错误信息到文件
		errPath := filepath.Join(s.workDir, "compile_error.txt")
		os.WriteFile(errPath, stderrBuf.Bytes(), 0644)

		return fmt.Errorf("compilation failed: %w\n%s", err, stderrBuf.String())
	}

	// 确定可执行文件路径
	switch s.input.Language {
	case "cpp":
		s.executable = filepath.Join(s.workDir, "main")
	case "java":
		s.executable = filepath.Join(s.workDir, "Main.class")
	default:
		s.executable = filepath.Join(s.workDir, "main")
	}

	return nil
}

/*
*
RunTestCase 执行单个测试用例
*/
func (s *Sandbox) RunTestCase(testCase models.TestCase) (*models.TestCaseResult, error) {
	result := &models.TestCaseResult{
		CaseID:   strconv.Itoa(testCase.CaseID),
		Stdin:    testCase.Stdin,
		Expected: testCase.Expected,
	}

	// 准备输入文件
	inputPath := filepath.Join(s.workDir, fmt.Sprintf("input_%d.txt", testCase.CaseID))
	if err := os.WriteFile(inputPath, []byte(testCase.Stdin), 0644); err != nil {
		result.Status = models.SystemError
		result.Stderr = fmt.Sprintf("Failed to create input file: %v", err)
		return result, nil
	}

	// 更新根文件系统内容
	if err := s.copyWorkDirToRootFS(); err != nil {
		result.Status = models.SystemError
		result.Stderr = fmt.Sprintf("Failed to update rootfs: %v", err)
		return result, nil
	}

	// 准备输出文件
	outputPath := filepath.Join(s.workDir, fmt.Sprintf("output_%d.txt", testCase.CaseID))
	stdoutFile, err := os.Create(outputPath)
	if err != nil {
		result.Status = models.SystemError
		result.Stderr = fmt.Sprintf("Failed to create output file: %v", err)
		return result, nil
	}
	defer stdoutFile.Close()

	// 准备错误输出
	stderrPath := filepath.Join(s.workDir, fmt.Sprintf("error_%d.txt", testCase.CaseID))
	stderrFile, err := os.Create(stderrPath)
	if err != nil {
		result.Status = models.SystemError
		result.Stderr = fmt.Sprintf("Failed to create error file: %v", err)
		return result, nil
	}
	defer stderrFile.Close()
	// 构建执行命令 - 使用实际的可执行文件路径
	var executable string
	var args []string

	switch s.input.Language {
	case "cpp":
		executable = filepath.Join(s.workDir, "main") // 使用绝对路径
		args = []string{}
	case "java":
		executable = "/usr/bin/java"
		args = []string{filepath.Join(s.workDir, "Main")}
	case "python", "python3":
		executable = "/usr/bin/python3" // 使用系统的python3
		args = []string{filepath.Join(s.workDir, "main.py")}
	default:
		executable = filepath.Join(s.workDir, "main")
		args = []string{}
	}

	// 暂时直接使用exec.Command，不使用命名空间管理器
	cmd := exec.Command(executable, args...)

	// 设置标准输入
	inputFile, _ := os.Open(inputPath)
	defer inputFile.Close()
	cmd.Stdin = inputFile

	// 设置标准输出和错误
	cmd.Stdout = stdoutFile
	cmd.Stderr = stderrFile

	// 设置环境变量
	cmd.Env = []string{
		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
		"LANG=C.UTF-8",
		"HOME=" + s.workDir,
		"TMPDIR=" + s.workDir,
	}

	// 启动进程
	startTime := time.Now()
	if err := cmd.Start(); err != nil {
		result.Status = models.SystemError
		result.Stderr = fmt.Sprintf("Failed to start process: %v", err)
		return result, nil
	}

	// 将进程加入cgroup（忽略错误，因为cgroup可能不存在）
	if err := s.cgroupMgr.AddProcess(cmd.Process.Pid); err != nil {
		logger.Debug("Failed to add process to cgroup:", err)
		// 不终止进程，继续执行
	}

	// 等待进程完成或超时
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case err := <-done:
		// 进程正常退出
		elapsed := time.Since(startTime)
		result.Time = int(elapsed.Milliseconds())

		// 读取输出
		stdout, _ := os.ReadFile(outputPath)
		stderr, _ := os.ReadFile(stderrPath)
		result.Stdout = string(stdout)
		result.Stderr = string(stderr)

		// 获取内存使用情况
		memUsage, _ := s.cgroupMgr.GetMemoryUsage()
		result.Memory = int(memUsage / 1024) // KB

		// 确定状态
		if err != nil {
			if exitErr, ok := err.(*exec.ExitError); ok {
				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
					if status.Signaled() {
						switch status.Signal() {
						case syscall.SIGSYS:
							result.Status = models.RestrictedSystemCall
						case syscall.SIGSEGV:
							result.Status = models.RuntimeError
							result.Stderr = "Segmentation fault"
						case syscall.SIGXCPU:
							result.Status = models.TimeLimitExceeded
						case syscall.SIGXFSZ:
							result.Status = models.RuntimeError
							result.Stderr = "Output limit exceeded"
						default:
							result.Status = models.RuntimeError
							result.Stderr = fmt.Sprintf("Process signaled: %s", status.Signal())
						}
					} else {
						result.Status = models.RuntimeError
						result.Stderr = fmt.Sprintf("Exit code: %d", status.ExitStatus())
					}
				}
			} else {
				result.Status = models.RuntimeError
				result.Stderr = err.Error()
			}
		} else {
			// 检查输出是否正确
			if strings.TrimSpace(result.Stdout) == testCase.Expected {
				result.Status = models.Accepted
			} else {
				result.Status = models.WrongAnswer
			}
		}

		// 检查资源限制
		if result.Time > s.input.ResourcesLimits.CpuTime*1000 {
			result.Status = models.TimeLimitExceeded
		}
		if result.Memory*1024 > s.input.ResourcesLimits.MemoryBytes {
			result.Status = models.MemoryLimitExceeded
		}
		if len(result.Stdout) > s.input.ResourcesLimits.OutputBytes {
			result.Status = models.RuntimeError
			result.Stderr = "Output limit exceeded"
		}

		return result, nil

	case <-time.After(time.Duration(s.input.ResourcesLimits.CpuTime) * time.Second):
		// 超时处理
		cmd.Process.Kill()
		<-done // 等待进程真正退出

		result.Status = models.TimeLimitExceeded
		result.Time = s.input.ResourcesLimits.CpuTime * 1000

		// 尝试获取内存使用情况
		if memUsage, err := s.cgroupMgr.GetMemoryUsage(); err == nil {
			result.Memory = int(memUsage / 1024)
		}

		return result, nil
	}
}

/**
Judge 执行判题流程
*/

func (s *Sandbox) Judge() (*models.OutputResult, error) {
	// 初始化沙箱
	if err := s.Initialize(); err != nil {
		return nil, fmt.Errorf("initialization failed: %w", err)
	}
	defer s.Cleanup()

	// 编译代码（如果需要）
	if err := s.Compile(); err != nil {
		// 读取编译错误
		errMsg := err.Error()
		if errorFile, err := os.ReadFile(filepath.Join(s.workDir, "compile_error.txt")); err == nil {
			errMsg = string(errorFile)
		}

		return &models.OutputResult{
			SubmissionID: s.input.SubmissionID,
			Language:     s.input.Language,
			Code:         s.input.Code,
			Verdict:      models.CompilationError,
			Result: []models.TestCaseResult{
				{
					CaseID: "0",
					Stderr: errMsg,
					Status: models.CompilationError,
				},
			},
		}, nil
	}

	// 执行所有测试用例
	results := make([]models.TestCaseResult, 0, len(s.input.TestCases))
	overallVerdict := models.Accepted
	maxTime := 0
	maxMemory := 0

	for _, testCase := range s.input.TestCases {
		result, err := s.RunTestCase(testCase)
		if err != nil {
			return nil, fmt.Errorf("failed to run test case %d: %w", testCase.CaseID, err)
		}

		// 更新最大资源使用
		if result.Time > maxTime {
			maxTime = result.Time
		}
		if result.Memory > maxMemory {
			maxMemory = result.Memory
		}

		// 更新总体结果
		if result.Status != models.Accepted && overallVerdict == models.Accepted {
			overallVerdict = result.Status
		}

		results = append(results, *result)
	}

	// 返回判题结果
	return &models.OutputResult{
		SubmissionID: s.input.SubmissionID,
		Language:     s.input.Language,
		Code:         s.input.Code,
		Verdict:      overallVerdict,
		MaxTime:      maxTime,
		MaxMemory:    maxMemory,
		Result:       results,
	}, nil
}

/*
*
Cleanup 清理沙箱资源
*/
func (s *Sandbox) Cleanup() {
	// 清理cgroup
	if s.cgroupMgr != nil {
		s.cgroupMgr.Destroy()
	}

	// 清理命名空间
	if s.namespaceMgr != nil {
		s.namespaceMgr.Cleanup()
	}

	// 清理工作目录
	if s.workDir != "" {
		os.RemoveAll(s.workDir)
	}
}
